/**
 * 虚拟列表组件 - 支持动态高度和自定义渲染函数
 * @author AI Assistant
 * @version 1.0.0
 */
class UIVirtualList {
    /**
     * 构造函数
     * @param {HTMLElement} container - 容器元素
     * @param {Object} options - 配置选项
     * @param {number} options.itemHeight - 估算高度
     * @param {number} options.bufferSize - 缓冲区大小
     * @param {number} options.throttleDelay - 节流延迟（毫秒）
     * @param {number} options.pauseThreshold - 暂停渲染阈值（毫秒）
     * @param {number} options.itemCount - 数据列表的长度
     * @param {Function} options.renderItem - 自定义渲染函数
     */
    constructor(container, options = {}) {
        if (!(container instanceof HTMLElement)) {
            throw new Error('The container must be an HTMLElement.');
        }
        this.container = container;
        this.container.style.width = '100%'
        this.container.style.height = '100%'
        this.container.style.overflow = 'hidden auto'
        this.container.style.position = 'relative'

        this.options = {
            itemHeight: 80,     // 估算高度
            bufferSize: 5,      // 缓冲区大小
            throttleDelay: 16,  // 节流延迟（毫秒）
            pauseThreshold: 50, // 暂停渲染阈值（毫秒）
            itemCount: 0,       // 数据列表的长度
            renderItem: null,   // 自定义渲染函数
            ...options
        };

        // 验证渲染函数
        if (!this.options.renderItem || typeof this.options.renderItem !== 'function') {
            throw new Error('The renderItem must be a function.');
        }

        // 验证itemCount
        if (typeof this.options.itemCount !== 'number' || this.options.itemCount < 0) {
            throw new Error('The itemCount must be a non-negative number.');
        }

        this.positions = []; // 存储每个item的位置信息
        this.startIndex = 0;
        this.endIndex = 0;
        this.visibleCount = 0;

        // 滚动优化相关
        this.isScrolling = false;
        this.scrollTimer = null;
        this.renderTimer = null;
        this.lastScrollTime = 0;
        this.isPaused = false;
        this.pendingUpdate = false;

        this.init();
    }

    /**
     * 初始化虚拟列表
     */
    init() {
        this.container.innerHTML = `
            <div data-id="uvl-phantom" style="position: absolute;left: 0;top: 0;right: 0;z-index: -1;"></div>
            <div data-id="uvl-content" style="position: absolute;left: 0;top: 0;right: 0;"></div>
        `;

        this.phantom = this.container.querySelector('[data-id="uvl-phantom"]');
        this.content = this.container.querySelector('[data-id="uvl-content"]');

        this.visibleCount = Math.ceil(this.container.clientHeight / this.options.itemHeight)
            + this.options.bufferSize;

        this.bindEvents();
        this.initPositions();
        this.handleScroll();
    }

    /**
     * 绑定滚动事件
     */
    bindEvents() {
        // 使用节流处理滚动事件
        this.container.addEventListener('scroll', this.throttledScroll.bind(this));
    }

    /**
     * 节流滚动处理
     */
    throttledScroll() {
        const now = Date.now();
        const timeSinceLastScroll = now - this.lastScrollTime;

        // 检测是否为快速滚动
        if (timeSinceLastScroll < this.options.pauseThreshold) {
            this.pauseRendering();
        } else {
            this.resumeRendering();
        }

        this.lastScrollTime = now;

        // 清除之前的定时器
        if (this.renderTimer) {
            clearTimeout(this.renderTimer);
        }

        // 设置新的渲染定时器
        this.renderTimer = setTimeout(() => {
            if (!this.isPaused) {
                this.handleScroll();
            } else {
                this.pendingUpdate = true;
            }
        }, this.options.throttleDelay);

        // 设置滚动停止检测
        if (this.scrollTimer) {
            clearTimeout(this.scrollTimer);
        }

        this.scrollTimer = setTimeout(() => {
            this.onScrollEnd();
        }, 150); // 150ms后认为滚动结束
    }

    /**
     * 暂停渲染
     */
    pauseRendering() {
        if (!this.isPaused) {
            this.isPaused = true;
        }
    }

    /**
     * 恢复渲染
     */
    resumeRendering() {
        if (this.isPaused) {
            this.isPaused = false;

            // 如果有待处理的更新，立即执行
            if (this.pendingUpdate) {
                this.pendingUpdate = false;
                this.handleScroll();
            }
        }
    }

    /**
     * 滚动结束处理
     */
    onScrollEnd() {
        this.isScrolling = false;
        this.resumeRendering();

        // 确保最终状态正确
        this.handleScroll();
    }

    /**
     * 处理滚动事件
     */
    handleScroll() {
        if (this.options.itemCount === 0) {
            return;
        }

        const scrollTop = this.container.scrollTop;
        const containerHeight = this.container.clientHeight;
        const scrollHeight = this.container.scrollHeight;

        // 检查是否滚动到底部
        const isAtBottom = scrollTop + containerHeight >= scrollHeight - 1;

        if (isAtBottom) {
            // 如果滚动到底部，确保显示最后的数据
            this.endIndex = this.options.itemCount - 1;
            this.startIndex = Math.max(0, this.endIndex - this.visibleCount + 1);
        } else {
            this.startIndex = this.getStartIndex(scrollTop);
            this.endIndex = Math.min(this.startIndex + this.visibleCount, this.options.itemCount - 1);
        }

        this.updateVisibleData();
    }

    /**
     * 根据滚动位置获取起始索引（优化版）
     * @param {number} scrollTop - 滚动位置
     * @returns {number} 起始索引
     */
    getStartIndex(scrollTop) {
        // 如果scrollTop为0，直接返回0
        if (scrollTop <= 0) {
            return 0;
        }

        let start = 0;
        let end = this.positions.length - 1;
        let result = 0;

        while (start <= end) {
            const midIndex = Math.floor((start + end) / 2);
            const midValue = this.positions[midIndex].bottom;

            if (midValue === scrollTop) {
                return midIndex + 1;
            } else if (midValue < scrollTop) {
                result = midIndex + 1;
                start = midIndex + 1;
            } else {
                end = midIndex - 1;
            }
        }

        // 确保结果在有效范围内
        return Math.min(result, this.positions.length - 1);
    }

    /**
     * 更新可视区域数据
     */
    updateVisibleData() {
        // 如果渲染被暂停，标记为待更新
        if (this.isPaused) {
            this.pendingUpdate = true;
            return;
        }

        this.content.innerHTML = '';

        for (let i = this.startIndex; i <= this.endIndex; i++) {
            const itemElement = this.createItemElement(i);
            this.content.appendChild(itemElement);
        }

        // 更新content位置
        this.content.style.transform = `translate3d(0, ${this.getTransform()}px, 0)`;

        // 测量实际高度并更新位置信息
        this.$nextTick(() => {
            this.updateItemsSize();
        });
    }

    /**
     * 创建列表项元素（使用外部渲染函数）
     * @param {number} index - 索引
     * @returns {HTMLElement} 列表项元素
     */
    createItemElement(index) {
        try {
            // 调用外部渲染函数获取渲染结果
            const renderResult = this.options.renderItem(index);

            let element;

            if (typeof renderResult === 'string') {
                // 如果返回字符串，创建div并设置innerHTML
                element = document.createElement('div');
                element.innerHTML = renderResult;
            } else if (renderResult instanceof HTMLElement) {
                // 如果返回DOM元素，直接使用
                element = renderResult;
            } else {
                // 其他情况，抛出错误
                throw new Error('The renderItem function must return a string or a DOM element.');
            }

            // 设置必要的属性
            element.dataset.index = index;
            element.classList.add('virtual-list-item');

            return element;
        } catch (error) {
            console.error('Render error:', error);

            // 返回错误提示元素
            const errorElement = document.createElement('div');
            errorElement.className = 'virtual-list-item';
            errorElement.dataset.index = index;
            errorElement.innerHTML = `<div style="color: red;">Render error: ${error.message}</div>`;

            return errorElement;
        }
    }

    /**
     * 获取transform偏移量
     * @returns {number} 偏移量
     */
    getTransform() {
        return this.startIndex >= 1 ? this.positions[this.startIndex - 1].bottom : 0;
    }

    /**
     * 更新列表项尺寸信息
     */
    updateItemsSize() {
        const nodes = this.content.children;

        for (let i = 0; i < nodes.length; i++) {
            const node = nodes[i];
            const rect = node.getBoundingClientRect();
            const height = rect.height;
            const index = parseInt(node.dataset.index);

            const oldHeight = this.positions[index].height;
            const dValue = oldHeight - height;

            // 更新当前项高度
            this.positions[index].height = height;
            this.positions[index].bottom = this.positions[index].bottom - dValue;

            // 更新后续项的位置
            for (let k = index + 1; k < this.positions.length; k++) {
                this.positions[k].top = this.positions[k - 1].bottom;
                this.positions[k].bottom = this.positions[k].bottom - dValue;
            }
        }

        // 更新phantom高度
        const height = this.positions[this.positions.length - 1].bottom;
        this.phantom.style.height = height + 'px';
    }

    /**
     * 初始化位置信息
     */
    initPositions() {
        this.positions = [];
        for (let i = 0; i < this.options.itemCount; i++) {
            this.positions.push({
                index: i,
                height: this.options.itemHeight,
                top: i * this.options.itemHeight,
                bottom: (i + 1) * this.options.itemHeight
            });
        }

        // 设置phantom高度
        if (this.positions.length > 0) {
            this.phantom.style.height = this.positions[this.positions.length - 1].bottom + 'px';
        }
    }

    /**
     * 模拟nextTick
     * @param {Function} callback - 回调函数
     */
    $nextTick(callback) {
        setTimeout(callback, 0);
    }

    /**
     * 滚动到指定索引的项目
     * @param {number} index - 目标索引
     * @param {string} align - 对齐方式：'top'(顶部对齐), 'center'(居中), 'bottom'(底部对齐), 'auto'(自动)
     */
    scrollToIndex(index, align = 'auto') {
        // 参数验证
        if (typeof index !== 'number' || index < 0 || index >= this.options.itemCount) {
            console.warn(`Invalid index: ${index}. Index should be between 0 and ${this.options.itemCount - 1}.`);
            return;
        }

        // 获取容器高度
        const containerHeight = this.container.clientHeight;

        // 获取目标项的位置信息
        const targetPosition = this.positions[index];
        const targetTop = targetPosition.top;
        const targetBottom = targetPosition.bottom;
        const targetHeight = targetPosition.height;

        let scrollTop;

        switch (align) {
            case 'top':
                // 将目标项对齐到容器顶部
                scrollTop = targetTop;
                break;

            case 'center':
                // 将目标项居中显示
                scrollTop = targetTop - (containerHeight - targetHeight) / 2;
                break;

            case 'bottom':
                // 将目标项对齐到容器底部
                scrollTop = targetBottom - containerHeight;
                break;

            case 'auto':
            default:
                // 自动判断最佳滚动位置
                const currentScrollTop = this.container.scrollTop;
                const viewportTop = currentScrollTop;
                const viewportBottom = currentScrollTop + containerHeight;

                // 如果目标项已经完全在视口内，不需要滚动
                if (targetTop >= viewportTop && targetBottom <= viewportBottom) {
                    return;
                }

                // 如果目标项在视口上方，滚动到顶部对齐
                if (targetTop < viewportTop) {
                    scrollTop = targetTop;
                }
                // 如果目标项在视口下方，滚动到底部对齐
                else if (targetBottom > viewportBottom) {
                    scrollTop = targetBottom - containerHeight;
                }
                break;
        }

        // 确保滚动位置在有效范围内
        const maxScrollTop = this.container.scrollHeight - containerHeight;
        scrollTop = Math.max(0, Math.min(scrollTop, maxScrollTop));

        // 执行滚动
        this.container.scrollTop = scrollTop;

        // 立即更新视图以确保目标项被渲染
        this.handleScroll();
    }

    /**
     * 销毁组件
     */
    destroy() {
        // 清除定时器
        if (this.scrollTimer) {
            clearTimeout(this.scrollTimer);
        }
        if (this.renderTimer) {
            clearTimeout(this.renderTimer);
        }

        // 移除事件监听器
        this.container.removeEventListener('scroll', this.throttledScroll.bind(this));

        // 清空容器
        this.container.innerHTML = '';

        // 重置属性
        this.positions = [];
    }
}
